import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.apache.zookeeper.data.Stat;

import java.util.Collections;

/**
 * @author create on 2021/7/7
 * Curator 在zookeeper原生API的接口上进行了包装，解决很多Zookeeper非常底层的开发细节。
 * 提供各种应用场景(recipe， 比如：分布式锁服务、集群领导选举、共享计数器、缓存机制、分布式队列等)
 */
public class CuratorTest {
    public static void main(String[] args) throws Exception {
        String connIp =  "127.0.0.1";
        //重试策略
        ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3,Integer.MAX_VALUE);

        System.out.println("*********");
        CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(connIp, retryPolicy);
        curatorFramework.start();

        CuratorFramework curatorFramework2 = CuratorFrameworkFactory.builder().connectString(connIp)
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retryPolicy)
                .build();
        curatorFramework2.start();


        /**
         * 创建Zookeeper的持久节点，如果没有父节点，则自动创建
         */
//        curatorFramework.create().creatingParentsIfNeeded()
//                .withMode(CreateMode.PERSISTENT)
//                .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
//                .forPath("/node10/child_01", "1234576".getBytes());

        /**
         * 获取Zk上节点的数据信息和版本号
         */
        Stat node10Stat = new Stat();
        byte[] node10 = curatorFramework.getData()
                .storingStatIn(node10Stat)//获取stat信息存储到stat对象
                .forPath("/node10/child_01");
        System.out.println("=====>该节点信息为：" + new String(node10));
        System.out.println("=====>该节点的数据版本号为：" + node10Stat.getVersion());

        /**
         * 获取Zk数据
         * 该Watcher只会触发一次
         * 为了免去开发人员重复注册Watcher， 框架提供了高级封装。
         * NodeCache	监听节点对应增、删、改操作
         * PathChildrenCache	监听节点下一级子节点的增、删、改操作
         * TreeCache	可以将指定的路径节点作为根节点，对其所有的子节点操作进行监听，呈现树形目录的监听
         * https://blog.csdn.net/hosaos/article/details/88658676
         */
        byte[] dataBytes = curatorFramework.getData()
                .usingWatcher(new Watcher() {
                    public void process(WatchedEvent event) {
                        System.out.println("** 触发Watcher");
                        System.out.println(event);
                    }
                })
                .forPath("/node10/child_01");
        System.out.println("获取到节点数据为" + new String(dataBytes));

        /**
         * 设置zk的数据。
         */
        curatorFramework.setData().forPath("/node10/child_01", "abc".getBytes());

        /**
         * 检查节点是否存在
         *
         * ephemeralOwner > 0 零时节点
         * ephemeralOwner = 0 持久节点
         */
        Stat existsNodeStat = curatorFramework.checkExists().forPath("/node10");
        if(existsNodeStat == null){
            System.out.println("=====>节点不存在");
        }
        if(existsNodeStat.getEphemeralOwner() > 0){
            System.out.println("=====>临时节点");
        }else{
            System.out.println("=====>持久节点");
        }

        /**
         * 删除Zk节点，如果存在子节点，会报错。
         *  KeeperErrorCode = Directory not empty for /node10
         */
//        curatorFramework.delete().forPath("/node10");

        /**
         * 递归删除
         */
        curatorFramework.delete()
                .deletingChildrenIfNeeded()
                .forPath("/node10");

        curatorFramework.close();

//        curatorFramework.delete()
//                .guaranteed()
//                .forPath("/node");




    }
}
